package com.contactbook.web.client;

import java.util.HashMap;

import java.util.Map;
import java.util.Set;

import com.contactbook.web.client.dto.ContactDTO;
import com.contactbook.web.client.dto.GroupDTO;
import com.contactbook.web.client.dto.MaritalStatusDTO;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DecoratedTabPanel;
import com.google.gwt.user.client.ui.DecoratorPanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

public class AddContactWidget extends View {
	
	private static enum Mode { CREATE, UPDATE}
	private Mode mode;
	
	private static final String FIRST_NAME_TEXTBOX_SIZE = "125px";
	private static final String LAST_NAME_TEXTBOX_SIZE = "125px";
	private static final String EMAIL_TEXTBOX_SIZE = "150px";
	private static final String ADDRESS_TEXTBOX_SIZE = "280px";
	private static final String ZIPCODE_TEXTBOX_SIZE = "70px";
	private static final String TOWN_TEXTBOX_SIZE = "110px";
	private static final String COUNTRY_TEXTBOX_SIZE = "110px";
	private static final String AGE_TEXTBOX_SIZE = "30px";
	
	// Error messages
	private static final String THROWABLE_ERROR_1 = "You must enter a firstname and a lastname for the contact.";
	private static final String THROWABLE_ERROR_2 = "Zipcode must be a number.";

	// Title of the form
	private final static String TITLE_CREATE = "Add a contact to your contact book";
	private final static String TITLE_UPDATE = "Update a contact";
	
	private TextBox firstnameTb, lastnameTb, emailTb, addressTb, zipCodeTb, townTb, countryTb, ageTb;
	private ListBox maritalStatusLb, groupsLb = new ListBox();
	
	private Map<Integer, GroupDTO> groups = new HashMap<Integer, GroupDTO>();
	private Map<Integer, Integer> groupsIndex = new HashMap<Integer, Integer>();
	
	private VerticalPanel content;
	
	public AddContactWidget(ContactBook contactBook) {

		super(contactBook);
	}
	
	private class CancelHandler implements ClickHandler {
		public void onClick(ClickEvent event) {
			clearGroupsMaps();
			contactBook.switchView(Constants.ListOfContactsViewName);
		}
	}
	
	private class OkHandler implements ClickHandler {
		
		public void onClick(ClickEvent event) {
			String firstname = firstnameTb.getText();
			String lastname = lastnameTb.getText();
			String email = emailTb.getText();
			String address = addressTb.getText();
			String zipcode = zipCodeTb.getText();
			String town = townTb.getText();
			String country = countryTb.getText();
			String age = ageTb.getText();
			
		    int maritalstatus = maritalStatusLb.getSelectedIndex();
			
			if((!isNaN(zipcode) && !zipcode.isEmpty()) || zipcode.isEmpty()) {
				
				if(!firstname.isEmpty() && !lastname.isEmpty()) {
					
					ContactDTO contactDTO = new ContactDTO();
					contactDTO.setAccount(contactBook.getCurrentSession().getAccountLogged());
					contactDTO.setFirstName(firstname);
					contactDTO.setLastName(lastname);
					
					if (!email.isEmpty())
						contactDTO.setEmail(email);
					
					if (!address.isEmpty())
						contactDTO.setAddress(address);
					
					if (!zipcode.isEmpty())
						contactDTO.setZipCode(Integer.parseInt(zipcode));
					
					if (!town.isEmpty())
						contactDTO.setTown(town);
					
					if (!country.isEmpty())
						contactDTO.setCountry(country);
					
					if (!age.isEmpty())
						contactDTO.setAge(Integer.parseInt(age));
                   
					switch(maritalstatus) {
						case 0: contactDTO.setMaritalStatus(null);
							break;
						case 1: contactDTO.setMaritalStatus(MaritalStatusDTO.SINGLE);
							break;
						case 2: contactDTO.setMaritalStatus(MaritalStatusDTO.MARRIED);
							break;
						case 3: contactDTO.setMaritalStatus(MaritalStatusDTO.SEPARATED);
							break;
						case 4: contactDTO.setMaritalStatus(MaritalStatusDTO.DIVORCED);
							break;
						case 5: contactDTO.setMaritalStatus(MaritalStatusDTO.WIDOWED);
							break;
						case 6: contactDTO.setMaritalStatus(MaritalStatusDTO.ENGAGED);
							break;
						case 7: contactDTO.setMaritalStatus(MaritalStatusDTO.ANNULLED);
							break;
						case 8: contactDTO.setMaritalStatus(MaritalStatusDTO.COHABITATING);
							break;
						default: break;	
					}
					int groupSelected = groupsLb.getSelectedIndex();					
					
					if (groupSelected > 0) {
						contactDTO.setGroup(groups.get(groupSelected));
						if(mode == Mode.CREATE)
							addContact(contactDTO, contactDTO.getGroup().getId());
						else
							updateContact(contactDTO);
					} else {
						if(mode == Mode.CREATE)
							addContact(contactDTO);
						else
							updateContact(contactDTO);
					}
				} else
					new DialogBoxWidget(contactBook, THROWABLE_ERROR_1);
			} else
				new DialogBoxWidget(contactBook, THROWABLE_ERROR_2);			
		}
	}

	private boolean isNaN(String value) {
		if (value.isEmpty())
			return true;
		for (char c : value.toCharArray())
			if (c < '0' || c > '9')
				return true;
		return false;	
	}

	@Override
	public VerticalPanel getContent() {
		if (contactBook.isLogged()) {
			getGroupsList();
			buildView();
			clearWidget();
			if (contactBook.getCurrentSession().parameters.get(Constants.SessionParameterContactId) != null) {
				mode = Mode.UPDATE;
				int contactId = (Integer)contactBook.getCurrentSession().parameters.get((String)Constants.SessionParameterContactId);
				contactBook.getCurrentSession().parameters.remove(Constants.SessionParameterContactId);
				loadContact(contactId);
			} else
				mode = Mode.CREATE;
			return content;
		} else
			contactBook.switchView("login");
		return null;
	}
	
	public VerticalPanel getFullNamePanel() {
		
		VerticalPanel panelWidgets = new VerticalPanel();
		
		/* Header note label */		
		final Label labelNote = new Label("You must give the full name of the contact");
		labelNote.setStyleName("gwt-label-labelnote");
		
		final Label labelFirstname = new Label("First name :");
		final Label labelLastname = new Label("Last name :");
		final Label labelGroup = new Label("Group :");
				
		firstnameTb = new TextBox();
		lastnameTb = new TextBox();
		
		/* Form design */
		final FlexTable table = new FlexTable();
		
		table.setWidget(0, 0, labelFirstname);
		table.setWidget(0, 1, firstnameTb);
		
		table.setWidget(1, 0, labelLastname);
		table.setWidget(1, 1, lastnameTb);
		
		firstnameTb.setWidth(FIRST_NAME_TEXTBOX_SIZE);
		lastnameTb.setWidth(LAST_NAME_TEXTBOX_SIZE);
		
		/* Table properties */
		table.getFlexCellFormatter().setWidth(0, 0, "80px");
		table.getFlexCellFormatter().setHeight(1, 0, "50px");
		
		table.getFlexCellFormatter().setAlignment(1, 0, ALIGN_LEFT, ALIGN_MIDDLE);
		table.getFlexCellFormatter().setAlignment(1, 1, ALIGN_LEFT, ALIGN_MIDDLE);
		
		table.setCellPadding(3);
		
		Label labelNoteGroup = new Label("Affect to a group");
		labelNoteGroup.setStyleName("gwt-label-labelnote");
		
		final FlexTable tableGroup = new FlexTable();
		tableGroup.getFlexCellFormatter().setWidth(0, 0, "80px");
		
		tableGroup.setWidget(0, 0, labelGroup);
		tableGroup.setWidget(0, 1, groupsLb);
		
		groupsLb.setSelectedIndex(0);
		
		tableGroup.getFlexCellFormatter().setWidth(0, 0, "130px");
		
		panelWidgets.add(labelNote);
		panelWidgets.add(table);
		panelWidgets.add(labelNoteGroup);
		panelWidgets.add(tableGroup);
		
		return panelWidgets;
	}
	
	public VerticalPanel getDetailsPanel() {
		
		VerticalPanel panelWidgets = new VerticalPanel();
		
		/* Header note label */		
		final Label labelNote = new Label("How to join the contact");
		labelNote.setStyleName("gwt-label-labelnote");
		
		final Label labelEmail = new Label("Email :");
		final Label labelAddress = new Label("Address :");
		final Label labelZipcode = new Label("Zip code :");
		final Label labelTown = new Label("Town :");
		final Label labelCountry = new Label("Country :");
		
		emailTb = new TextBox();
		addressTb = new TextBox();
		zipCodeTb = new TextBox();
		townTb = new TextBox();
		countryTb = new TextBox();
		
		emailTb.setWidth(EMAIL_TEXTBOX_SIZE);
		addressTb.setWidth(ADDRESS_TEXTBOX_SIZE);
		zipCodeTb.setWidth(ZIPCODE_TEXTBOX_SIZE);
		townTb.setWidth(TOWN_TEXTBOX_SIZE);
		countryTb.setWidth(COUNTRY_TEXTBOX_SIZE);	
		
		zipCodeTb.setMaxLength(5);
		
		FlexTable table = new FlexTable();		
	
		table.setWidget(0, 0, labelAddress);
		table.setWidget(0, 1, addressTb);
		
		table.setWidget(1, 0, labelZipcode);
		table.setWidget(1, 1, zipCodeTb);
		
		table.setWidget(2, 0, labelTown);
		table.setWidget(2, 1, townTb);

		table.setWidget(3, 0, labelCountry);
		table.setWidget(3, 1, countryTb);
		
		table.setWidget(4, 0, labelEmail);
		table.setWidget(4, 1, emailTb);
		
		/* Table properties */
		table.getFlexCellFormatter().setHeight(4, 0, "50px");		
		table.getFlexCellFormatter().setAlignment(4, 0, ALIGN_LEFT, ALIGN_MIDDLE);
		table.getFlexCellFormatter().setAlignment(4, 1, ALIGN_LEFT, ALIGN_MIDDLE);
		
		table.setCellPadding(3);
		
		panelWidgets.add(labelNote);
		panelWidgets.add(table);
		
		return panelWidgets;
	}
	
	public VerticalPanel getOtherInformations() {
		
		VerticalPanel panelWidgets = new VerticalPanel();
		
		/* Header note label */		
		final Label labelNote = new Label("You can give other information");
		labelNote.setStyleName("gwt-label-labelnote");
		
		final Label labelAge = new Label("Age :");
		final Label labelMaritalstatus = new Label("Marital status :");
		
		ageTb = new TextBox();
		maritalStatusLb = new ListBox();
		maritalStatusLb.addItem("", "0");
		maritalStatusLb.addItem("Single", "1");
		maritalStatusLb.addItem("Married", "2");
		maritalStatusLb.addItem("Separated", "3");
		maritalStatusLb.addItem("Divorced", "4");
		maritalStatusLb.addItem("Widowed", "5");
		maritalStatusLb.addItem("Engaged", "6");
		maritalStatusLb.addItem("Annulled", "7");
		maritalStatusLb.addItem("Cohabitating", "8");
		
		/* Form design */
		final FlexTable table = new FlexTable();
		
		table.setWidget(0, 0, labelAge);
		table.setWidget(0, 1, ageTb);
		
		table.setWidget(1, 0, labelMaritalstatus);
		table.setWidget(1, 1, maritalStatusLb);
		
		ageTb.setWidth(AGE_TEXTBOX_SIZE);
		ageTb.setMaxLength(3);
		
		/* Table properties */
		table.getFlexCellFormatter().setHeight(1, 0, "50px");		
		table.getFlexCellFormatter().setAlignment(1, 0, ALIGN_LEFT, ALIGN_MIDDLE);
		table.getFlexCellFormatter().setAlignment(1, 1, ALIGN_LEFT, ALIGN_MIDDLE);
		
		table.setCellPadding(3);
		
		panelWidgets.add(labelNote);
		panelWidgets.add(table);
		
		return panelWidgets;
	}
	
	public VerticalPanel buildView() {

		content = new VerticalPanel();
		
		DecoratorPanel panelAddContact = new DecoratorPanel();
		VerticalPanel panelWidgets = new VerticalPanel();
		
	    DecoratedTabPanel tabPanel = new DecoratedTabPanel();
	    tabPanel.setWidth("500px");
	    tabPanel.setAnimationEnabled(true);
	    
	    HorizontalPanel panelFullName = new HorizontalPanel();
	    panelFullName.setWidth("130px");
	    Label labelFullName = new Label(Constants.TAB_TITLE_1);
	    labelFullName.setStyleName("gwt-label-tabTitle");
	    panelFullName.add(labelFullName);
	    tabPanel.add(getFullNamePanel(), panelFullName);

	    HorizontalPanel panelDetails = new HorizontalPanel();
	    panelDetails.setWidth("100px");
	    Label labelDetails = new Label(Constants.TAB_TITLE_2);
	    labelDetails.setStyleName("gwt-label-tabTitle");
	    panelDetails.add(labelDetails);
	    tabPanel.add(getDetailsPanel(), panelDetails);
	    
	    HorizontalPanel panelOtherInformation = new HorizontalPanel();
	    panelOtherInformation.setWidth("180px");
	    Label labelOtherInformation = new Label(Constants.TAB_TITLE_3);
	    labelOtherInformation.setStyleName("gwt-label-tabTitle");
	    panelOtherInformation.add(labelOtherInformation);
	    tabPanel.add(getOtherInformations(), panelOtherInformation);
    
	    tabPanel.selectTab(0);
	    
	    // Buttons
	    FlexTable tableButtons = new FlexTable();
	    tableButtons.setWidth("500px");
	    tableButtons.setCellPadding(0);
	    tableButtons.setCellSpacing(0);
	    tableButtons.getCellFormatter().setWidth(0, 0, "250px");
	    tableButtons.getCellFormatter().setWidth(0, 1, "250px");
	    			
		final Button buttonOk = new Button("Ok");
		buttonOk.addClickHandler(new OkHandler());
		buttonOk.setStyleName("buttonform");
		
		final Button buttonCancel = new Button("Back");
		buttonCancel.addClickHandler(new CancelHandler());
		buttonCancel.setStyleName("buttonform");
		
		tableButtons.setWidget(10, 0, buttonOk);
		tableButtons.setWidget(10, 1, buttonCancel);
		
		/* Table properties */
		tableButtons.getFlexCellFormatter().setHeight(10, 0, "40px");
		
		tableButtons.getFlexCellFormatter().setAlignment(10, 0, ALIGN_CENTER, ALIGN_MIDDLE);
		tableButtons.getFlexCellFormatter().setAlignment(10, 1, ALIGN_CENTER, ALIGN_MIDDLE);
		
		tableButtons.setCellPadding(3);
				
		panelWidgets.add(tabPanel);
		panelWidgets.add(tableButtons);
		panelWidgets.setSpacing(5);
		
		panelAddContact.add(panelWidgets);
		
		content.add(panelAddContact);
				
		return content;
	}

	@Override
	public String getTitle() {
		if (mode == Mode.CREATE)
			return TITLE_CREATE;
		else
			return TITLE_UPDATE;
	}
	
	private void getGroupsList() {
	    final AsyncCallback<Set<GroupDTO>> callback = new AsyncCallback<Set<GroupDTO>>() {

			@SuppressWarnings("deprecation")
			@Override
			public void onFailure(Throwable caught) {
				content = new ErrorPanel();
			}

			@Override
			public void onSuccess(Set<GroupDTO> result) {
				int i = 1;
				groupsLb.addItem("default group", "0");
				for(GroupDTO groupDTO : result) {
					groupsLb.addItem(groupDTO.getName(), String.valueOf(groupDTO.getId()));
					groups.put(i, groupDTO);
					groupsIndex.put(groupDTO.getId(), i);
					i++;
				}
			}
		};
		contactBook.getGroupService().getGroups(contactBook.getCurrentSession().getLogin(), contactBook.getCurrentSession().getPassword(), callback);
	}
	
	private void addContact(ContactDTO contactDTO) {
		AsyncCallback<ContactDTO> callback = new AsyncCallback<ContactDTO>() {

			@SuppressWarnings("deprecation")
			@Override
			public void onFailure(Throwable caught) {
				content.clear();
				content.add(new ErrorPanel());								
			}

			@Override
			public void onSuccess(ContactDTO result) {
				clearGroupsMaps();
				DialogBoxWidget dialog = new DialogBoxWidget(contactBook, result.getFirstName() + " " + result.getLastName() + " has been added to your contact book");
				dialog.onHide("listOfContacts");
			}
		};
		contactBook.getContactService().add(contactDTO, contactBook.getCurrentSession().getLogin(), contactBook.getCurrentSession().getPassword(), callback);
	}
	
	private void addContact(ContactDTO contactDTO, int groupId) {
		AsyncCallback<ContactDTO> callback = new AsyncCallback<ContactDTO>() {

			@SuppressWarnings("deprecation")
			@Override
			public void onFailure(Throwable caught) {
				content.clear();
				content.add(new ErrorPanel());								
			}

			@Override
			public void onSuccess(ContactDTO result) {
				clearGroupsMaps();
				contactBook.switchView("listOfContacts");
			}
		};
		contactBook.getContactService().add(contactDTO, contactDTO.getGroup().getId(), contactBook.getCurrentSession().getLogin(), contactBook.getCurrentSession().getPassword(), callback);
	}
	
	private void updateContact(ContactDTO contactDTO) {
		AsyncCallback<Void> callback = new AsyncCallback<Void>() {

			@SuppressWarnings("deprecation")
			@Override
			public void onFailure(Throwable caught) {
				content.clear();
				content.add(new ErrorPanel());								
			}

			@Override
			public void onSuccess(Void result) {
				clearGroupsMaps();
				contactBook.switchView("listOfContacts");
			}
		};
		contactBook.getContactService().update(contactDTO, contactBook.getCurrentSession().getLogin(), contactBook.getCurrentSession().getPassword(), callback);
	}
		
	private void loadContact(int contactId) {
		AsyncCallback<ContactDTO> callback = new AsyncCallback<ContactDTO>() {

			@SuppressWarnings("deprecation")
			@Override
			public void onFailure(Throwable caught) {
				content.clear();
				content.add(new ErrorPanel());								
			}

			@Override
			public void onSuccess(ContactDTO result) {
				firstnameTb.setText(result.getFirstName());
				lastnameTb.setText(result.getLastName());
				emailTb.setText(result.getEmail());
				addressTb.setText(result.getAddress());
				
				if (result.getZipCode() != 0)
					zipCodeTb.setText(String.valueOf(result.getZipCode()));
				
				countryTb.setText(result.getCountry());
				
				if (result.getAge() != 0)
					ageTb.setText(String.valueOf(result.getAge()));
				
				
				switch(result.getMaritalStatus()) {
				case SINGLE:
					maritalStatusLb.setSelectedIndex(1);
					break;
				case MARRIED:
					maritalStatusLb.setSelectedIndex(2);
					break;
				case SEPARATED:
					maritalStatusLb.setSelectedIndex(3);
					break;
				case DIVORCED:
					maritalStatusLb.setSelectedIndex(4);
					break;
				case WIDOWED:
					maritalStatusLb.setSelectedIndex(5);
					break;
				case ENGAGED:
					maritalStatusLb.setSelectedIndex(6);
					break;
				case ANNULLED:
					maritalStatusLb.setSelectedIndex(7);
					break;
				case COHABITATING:
					maritalStatusLb.setSelectedIndex(8);
					break;
				default:
					break;
				}

				groupsLb.clear();
				int indexGroup = 0;
				
				for (int i=1; i<groups.size(); i++) {
					groupsLb.addItem(groups.get(i).getName());
					if (result.getId() == groups.get(i).getId())
						indexGroup = i;
				}
				groupsLb.setSelectedIndex(indexGroup);
			}
		};
		contactBook.getContactService().getContactById(contactId, contactBook.getCurrentSession().getLogin(), contactBook.getCurrentSession().getPassword(), callback);
	}

	
	private void clearWidget() {
		firstnameTb.setText("");
		lastnameTb.setText("");
		emailTb.setText("");
		addressTb.setText("");
		zipCodeTb.setText("");
		countryTb.setText("");
		ageTb.setText("");
		maritalStatusLb.setSelectedIndex(0);
	}
	
	private void clearGroupsMaps() {
		groupsLb.clear();
		groups.clear();
		groupsIndex.clear();
	}
}
